#ifndef AVALON_HANDLE_HPP
#define AVALON_HANDLE_HPP
#include <boost/noncopyable.hpp>
#include "Avalon/Base/Base.hpp"

namespace Avalon {

  /*! \class Handle
   *  \brief Pointer type with a flag specifying whether the pointer is owned.
   */
  template<typename T>
  class Handle : private boost::noncopyable {
    public:

      //! Constructs a Handle.
      Handle()
          : m_owned(false) {}

      //! Constructs a Handle to a reference, held pointer will not be owned.
      /*!
        \param instance The reference to hold.
      */
      Handle(T& instance)
          : m_instance(&instance),
            m_owned(false) {}

      //! Constructs a Handle.
      /*!
        \param instance The instance to hold.
        \param owned Whether the held <i>instance</i> is owned by this Handle.
      */
      Handle(T* instance, bool owned = true)
          : m_instance(instance),
            m_owned(owned) {}

      //! Constructs a Handle from a Carry, used when passing a parameter.
      /*!
        \param carry The Carry to construct the Handle from, if the Carry holds
                     a reference the the underlying pointer is not owned,
                     otherwise it is.
      */
      Handle(const Carry<T>& carry)
          : m_instance(carry.m_instance),
            m_owned(carry.m_pointer) {}

      ~Handle() {
        if(m_owned) {
          delete m_instance;
        }
      }

      //! Returns a reference to the held instance.
      T& operator *() {
        return *m_instance;
      }

      //! Returns a reference to the held instance.
      const T& operator *() const {
        return *m_instance;
      }

      //! Returns a pointer to the held instance.
      T* operator ->() {
        return m_instance;
      }

      //! Returns a pointer to the held instance.
      const T* operator ->() const {
        return m_instance;
      }

      //! Resets to hold nothing.
      void Reset() {
        if(m_owned) {
          delete m_instance;
        }
        m_owned = false;
      }

      //! Resets the instance held to a reference, will not own the reference.
      /*!
        \param instance The reference to hold.
      */
      void Reset(T& instance) {
        if(m_owned) {
          delete m_instance;
        }
        m_instance = &instance;
        m_owned = false;
      }

      //! Resets the instance to a pointer.
      /*!
        \param instance The instance to hold.
        \param owned Whether the held <i>instance</i> is owned by this Handle.
      */
      void Reset(T* instance, bool owned = true) {
        if(m_owned) {
          delete m_instance;
        }
        m_instance = instance;
        m_owned = owned;
      }

    private:
      T* m_instance;
      bool m_owned;
  };

  /*! \class Carry
   *  \brief Used to pass a pointer/reference to a Handle as a parameter.
   */
  template<typename T>
  class Carry {
    public:

      //! Constructs a Carry.
      Carry()
          : m_instance(NULL),
            m_pointer(true) {}

      //! Constructs a Carry from a pointer.
      /*!
        \param instance The pointer to pass, the pointer will be owned by the
                        corresponding Handle.
      */
      Carry(T* instance)
          : m_instance(instance),
            m_pointer(true) {}

      //! Constructs a Carry from a reference.
      /*!
        \param instance The reference to pass, the reference will not be owned
                        by the corresponding Handle.
      */
      Carry(T& instance)
          : m_instance(&instance),
            m_pointer(false) {}

      //! Returns a reference to the held instance.
      T& operator *() {
        return *m_instance;
      }

      //! Returns a reference to the held instance.
      const T& operator *() const {
        return *m_instance;
      }

      //! Returns a pointer to the held instance.
      T* operator ->() {
        return m_instance;
      }

      //! Returns a pointer to the held instance.
      const T* operator ->() const {
        return m_instance;
      }

    private:
      friend class Handle<T>;
      T* m_instance;
      bool m_pointer;
  };
}

#endif // AVALON_HANDLE_HPP
